package com.dandandog.framework.mapstruct;


import cn.hutool.core.util.ArrayUtil;
import com.dandandog.framework.mapstruct.context.BaseContext;
import org.mapstruct.Context;
import org.mapstruct.InheritConfiguration;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.MappingTarget;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Type;

/**
 * @author JohnnyLiu
 */
public interface IMapper<From, To> {

    default FromToKey key() {
        Type[] genericInterfaces = this.getClass().getGenericInterfaces();
        Type target = ArrayUtil.isEmpty(genericInterfaces) ? this.getClass().getGenericSuperclass() : genericInterfaces[0];
        Type[] types = ((ParameterizedTypeImpl) ((Class) (target)).getGenericInterfaces()[0]).getActualTypeArguments();
        if (types.length == 0) {
            throw new IllegalArgumentException(this.getClass().toString());
        }
        Class<?>[] genericTypes = new Class[types.length];
        for (int i = 0; i < types.length; i++) {
            genericTypes[i] = (Class<?>) types[i];
        }
        return new FromToKey(genericTypes[0], genericTypes[1]);
    }


    /**
     * Maps from one object to another.
     *
     * @param from 原对象
     * @return to
     */
    To mapTo(From from);


    /**
     * Maps to one object from another.
     *
     * @param to 映射对象
     * @return from 原对象
     */
    @InheritInverseConfiguration(name = "mapTo")
    From mapFrom(To to);


    /**
     * Maps from one object to another.
     *
     * @param from    原对象
     * @param context 填充内容
     * @return 映射对象
     */
    @InheritConfiguration(name = "mapTo")
    To mapContextTo(From from, @Context BaseContext<To> context);


    /**
     * Maps to one object from another.
     *
     * @param to      映射对象
     * @param context BaseContext
     * @return from 原对象
     */
    @InheritInverseConfiguration(name = "mapTo")
    From mapContextFrom(To to, @Context BaseContext<From> context);

    /**
     * Update the object.
     *
     * @param from 原对象
     * @param to   映射对象
     * @return 映射对象
     */
    @InheritConfiguration(name = "mapTo")
    To updateTo(From from, @MappingTarget To to);


    /**
     * Update the object.
     *
     * @param from 原对象
     * @param to   映射对象
     * @return 映射对象
     */
    @InheritInverseConfiguration(name = "mapTo")
    From updateFrom(To to, @MappingTarget From from);
}
